/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

package cz.muni.fi.pb138.webrep;

import cz.muni.fi.pb138.webrep.metadata.processors.XsdMetadataProcessor;
import cz.muni.fi.pb138.webrep.metadata.processors.WsdlMetadataProcessor;
import cz.muni.fi.pb138.webrep.metadata.processors.WarMetadataProcessor;
import cz.muni.fi.pb138.webrep.repositories.ArtifactRepository;
import java.io.File;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;
import org.basex.core.Context;

/**
 *
 * @author MojmírOdehnal
 */
@WebServlet(name = "UploadArtifactServlet", urlPatterns = {"/upload"})
@MultipartConfig(fileSizeThreshold=10*1024*1024,    // 10 MB
                 maxFileSize=50*1024*1024,       // 50 MB
                 maxRequestSize=50*1024*1024)       // 50 MB
public class UploadArtifactServlet extends HttpServlet {
    public static final String UPLOAD_DIR = "artifacts";
    
    private boolean isExtensionSupported(String extension) {
        switch(extension.toLowerCase()) {
            case "war": 
            case "xsd": 
            case "wsdl": 
                return true;
        }
        return false;
    }
    public boolean extractAndStoreMetadata(String pathToFile, String extension) throws IOException {
        switch(extension.toLowerCase()) {
            case "war": 
                return (new WarMetadataProcessor()).process(pathToFile);
            case "xsd": 
                return (new XsdMetadataProcessor()).process(pathToFile);
            case "wsdl": 
                return (new WsdlMetadataProcessor()).process(pathToFile);
        }
        return false;
    }
    
    /**
     * Handles the HTTP <code>POST</code> method.
     *
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        // code has basis in example http://www.journaldev.com/2122/servlet-3-file-upload-using-multipartconfig-annotation-and-part-interface
        Context context = new Context();
        // gets absolute path of the web application
        String applicationPath = request.getServletContext().getRealPath("");
        // constructs path of the directory to save uploaded file
        String uploadFilePath = applicationPath + File.separator + UPLOAD_DIR;
        
        String indexJspUrl = request.getContextPath()+"/";
        
        // creates the save directory if it does not exists
        File fileSaveDir = new File(uploadFilePath);
        if (!fileSaveDir.exists()) {
            fileSaveDir.mkdirs();
        }
        
        ArtifactRepository repo = new ArtifactRepository();
        //Get all the parts from request and write it to the file on server
        for (Part part : request.getParts()) {
            String filename = getFileName(part);
            String extension = "";
            int i = filename.lastIndexOf('.');
            if (i > 0) {
                extension = filename.substring(i+1);
            }
            if(!isExtensionSupported(extension)) {
                response.sendRedirect(indexJspUrl+"?msg=2");
                return;
            }
            if(!filename.matches("^[\\x20-\\x7e]*$")) { // some of chars are not in ASCII
                response.sendRedirect(indexJspUrl+"?msg=3");
                return;
            }
            repo.addArtifactRecord(filename);
            
            File artifactDir = new File(uploadFilePath + File.separator + filename);
            if (!artifactDir.exists()) {
                artifactDir.mkdirs();
            }
            
            String pathToFile = artifactDir.getPath() + File.separator 
                    + repo.getArtifactVersionsCount(filename);
            
            part.write(pathToFile);
            
            if(!extractAndStoreMetadata(pathToFile, extension)) {
                repo.deleteVersionBecauseItsProcessingFailed(filename);
                response.sendRedirect(indexJspUrl+"?msg=4");
                return;
            }
        }
        
        response.sendRedirect(indexJspUrl+"?msg=1");
    }
    /**
     * Utility method to get file name from HTTP header content-disposition
     */
    private String getFileName(Part part) {
        String contentDisp = part.getHeader("content-disposition");
        String[] tokens = contentDisp.split(";");
        for (String token : tokens) {
            if (token.trim().startsWith("filename")) {
                return token.substring(token.indexOf("=") + 2, token.length()-1);
            }
        }
        return "";
    }

    /**
     * Handles the HTTP <code>GET</code> method.
     *
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, "Can't upload via GET method");
    }

    /**
     * Returns a short description of the servlet.
     *
     * @return a String containing servlet description
     */
    @Override
    public String getServletInfo() {
        return "Handles artifact file upload";
    }

}
